package vm

import (
	"github.com/ledgerwatch/erigon/common"
	"github.com/ledgerwatch/erigon/core/types"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	lumberjackV2 "gopkg.in/natefinch/lumberjack.v2"
	"math/big"
)

type valueTransfer struct {
	depth           int
	transactionHash common.Hash
	from            common.Address
	fromBalance     *big.Int
	to              common.Address
	toBalance       *big.Int
	value           *big.Int
	kind            string
}

type TransactionTrace struct {
	src            common.Address
	hash           common.Hash
	blockNumber    *big.Int
	blockHash      common.Hash
	stack          []*valueTransfer
	txIndex        int
	err            error
	isOnlyContract bool
}

func NewTransactionTrace(blockHash common.Hash, blockNumber *big.Int, msg *types.Message, indexTx int, txHash common.Hash, onlyContract bool) *TransactionTrace {
	return &TransactionTrace{
		src:            msg.From(),
		hash:           txHash,
		blockNumber:    blockNumber,
		blockHash:      blockHash,
		stack:          make([]*valueTransfer, 0),
		txIndex:        indexTx,
		isOnlyContract: onlyContract,
	}
}

func (tt *TransactionTrace) saveToLog(err error) {
	for i, v := range tt.stack {
		if err != nil {
			Logger.Error("Run Tx Failed", zap.Uint64("BlockNumber", tt.blockNumber.Uint64()), zap.Int("txIndex", tt.txIndex), zap.String("from", v.from.String()), zap.String("to", v.to.String()), zap.Uint64("value", v.value.Uint64()), zap.Int("index", i))
		} else {
			Logger.Info("Run Tx Success", zap.Uint64("BlockNumber", tt.blockNumber.Uint64()), zap.Int("txIndex", tt.txIndex), zap.String("from", v.from.String()), zap.String("to", v.to.String()), zap.Uint64("value", v.value.Uint64()), zap.Int("index", i))
		}
	}
}

func (tt *TransactionTrace) addTraceTx(from, to common.Address, value *big.Int) {
	vt := &valueTransfer{
		from:  from,
		to:    to,
		value: value,
		kind:  "Internal Transaction",
	}

	tt.stack = append(tt.stack, vt)
}

var (
	Logger   *zap.Logger
	LogLevel zapcore.Level = zapcore.DebugLevel
	Sugger   *zap.SugaredLogger
)

func init() {
	writeSyncer := getLogWriter()
	encoder := getEncoder()
	core := zapcore.NewCore(encoder, writeSyncer, LogLevel)

	Logger = zap.New(core, zap.AddCaller())
	Sugger = Logger.Sugar()
}

func getEncoder() zapcore.Encoder {
	encoderConfig := zap.NewDevelopmentEncoderConfig()
	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
	encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
	return zapcore.NewConsoleEncoder(encoderConfig)
}

func getLogWriter() zapcore.WriteSyncer {
	lumberjack := &lumberjackV2.Logger{
		Filename:   "./logger.log", // 文件名
		MaxSize:    100,            // log文件最大MB
		MaxBackups: 100,            // log文件最大备份数
		MaxAge:     30,             // 最长保存时间
		Compress:   false,          // 是否压缩
	}

	return zapcore.AddSync(lumberjack)
	//return zapcore.NewMultiWriteSyncer(os.Stdout, zapcore.AddSync(lumberjack))
}
